using System;
using System.Collections;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Drawing;
using System.Collections.Specialized;
using System.Xml.Serialization;

namespace WebApplication
{
	[Serializable]
	public class GameboardHexCollection : ICollection
	{
		private ArrayList  _aGameboardHexs;

		public GameboardHex Find (string sHex)
		{
			GameboardHex returnHex = null;

			foreach (GameboardHex hex in _aGameboardHexs)
			{
				if (hex.Location == sHex)
				{
					returnHex = hex;
					break;
				}
			}

			return returnHex;
		}

		public GameboardHex this [string index]   // indexer declaration
		{ 
			get
			{
				return this.Find (index);
				//				return (GameboardHex) _aGameboardHexs[index];
			}

			set
			{
				GameboardHex	hex = this.Find (index);

				if (hex != null)
				{
					hex = value;
				}
			}
		}


		public GameboardHex this [int index]   // indexer declaration
		{ 
			get
			{
				return (GameboardHex) _aGameboardHexs[index];
			}

			set
			{
				_aGameboardHexs[index] = value;
			}
		}

		public void CopyTo(Array a, int index)
		{
			_aGameboardHexs.CopyTo(a, index);
		}
		public object SyncRoot
		{
			get{return this;}
		}
		public bool IsSynchronized
		{
			get{return false;}
		}

		public int Count
		{
			get
			{
				return _aGameboardHexs.Count;
			}
		}

		public GameboardHexCollection ()
		{
			_aGameboardHexs = new ArrayList ();
		}

		public void Add (System.Object GameboardHexCompany)
		{
			_aGameboardHexs.Add (GameboardHexCompany);
		}

		public void Add (GameboardHex GameboardHex)
		{
			_aGameboardHexs.Add (GameboardHex);
		}

		public void Remove (GameboardHex GameboardHex)
		{
			_aGameboardHexs.Remove (GameboardHex);
		}

		// IEnumerable Interface Implementation:

		public IEnumerator GetEnumerator() // non-IEnumerable version
		{
			return _aGameboardHexs.GetEnumerator ();
		}

		IEnumerator IEnumerable.GetEnumerator() // IEnumerable version
		{
			//			return (IEnumerator) new GameboardHexEnumerator(this);
			return _aGameboardHexs.GetEnumerator ();
		}
	}

	[Serializable]
	public class GameboardHex
	{
		public const int hexWidth = 81;
		public const int hexHeight = 71;

		private Color				_initialColor;
		[NonSerialized] private ImageButton			_button;
		private int					_nRotation;  // Rotation in degrees, 60, 120, 180, 240, 300 or 0.
		private Tile				_tile;
		private TokenCollection		_tokens;
		private Hashtable /*MyDictionary<Side, SideCollection>*/ _existingRoutes;
		private Hashtable /*MyDictionary<Side, SideCollection>*/ _newRoutes;		// Used during tile placement or tile rotation before being made permanent by copying to existing routes.  Temp storage area.
		private string				_initialTile;
		private string				_finalTile;
		private bool				_separateCities; // Tile 59 and toronto, used for token placement.
		private string				_city;
		private Game				_game;
		private string				_values;

		// JoeB - these will be filled in by calling TrackSegment.CalculateHexRoutes(this) whenever a tile is layed in this hex
		public TrackSegment [] TrackSegments = null;

		public City [] Cities = null;

		public string Values
		{
			get { return _values; }
			set { _values = value; }
		}

		//[XmlIgnore]   // TODO  Jeff, set this backpointer up when loading.
		public Game Game
		{
			get { return _game; }
			set { _game = value; }
		}

		public string City
		{
			get { return _city; }
			set { _city = value; }
		}

		public bool SeperateCities
		{
			get { return _separateCities; }
			set { _separateCities = value; }
		}

		public string InitialTile
		{
			get { return _initialTile; }
			set { _initialTile = value; }
		}

		public string FinalTile
		{
			get { return _finalTile; }
			set { _finalTile = value; }
		}

        //[XmlIgnore]  // JWF 10.12.07  Debugging
        public TokenCollection Tokens
		{
			get { return _tokens; }
		}

		public bool CanUpgradeTo (Game game, Tile tile, ref string sError)
		{
			bool	bReturn = false;

			if (this._tile.ValidUpgrades.Contains (tile.Name))
			{
				bReturn = true;

				if (!game.CanTownsBeUpgradedAndDownGraded)	// See if this is a town that is being upgraded to a city
				{
					if ((this._tile.TownType == WebApplication.Tile.eTileTownType.DblTown) || 
						(this._tile.TownType ==  WebApplication.Tile.eTileTownType.Town))
					{
						sError = "Can't upgrade or downgrade towns until a six train is bought.";
						bReturn = false;
					}
				}
			}
			else if (this.FinalTile == tile.Name)
			{
				Tile	newTile = game.Tiles[this.FinalTile];

				if (newTile != null)
				{
					switch (this._tile.Color)
					{
						case WebApplication.Tile.eTileColor.Yellow:
							if (newTile.Color == WebApplication.Tile.eTileColor.Green) // Never happens in 1856
							{
								bReturn = true;
							}
							else
							{
								sError = "Invalid color.  Upgrade yellow to green.";
							}
							break;

						case WebApplication.Tile.eTileColor.Green:
							if (newTile.Color == WebApplication.Tile.eTileColor.Brown) // 'L' tiles, Barrie and London.
							{
								bReturn = true;
							}
							else
							{
								sError = "Invalid color.  Upgrade green to brown.";
							}
							break;

						case WebApplication.Tile.eTileColor.Brown:
							if (newTile.Color == WebApplication.Tile.eTileColor.Gray) // Toronto and Hamilton
							{
								bReturn = true;
							}
							else
							{
								sError = "Invalid color.  Upgrade brown to gray.";
							}
							break;

						case WebApplication.Tile.eTileColor.Gray:  // Can't upgrade a gray tile.
							sError = "Tile doesn't upgrade further.";
							bReturn = false;	
							break;

						default:
							sError = "Invalid color for upgrade.";
							bReturn = false;
							break;
					}
				}
			}
			else
			{
				sError = "Invalid upgrade.  Valid upgrades: ";
				
				foreach (string sTile in _tile.ValidUpgrades)
				{
					sError += sTile;
					sError += " ";
				}

				if (this.FinalTile != null)
				{
					if (this.FinalTile.Length > 0)
					{
						sError += " final tile, " + this.FinalTile;
					}
				}
			}

			return bReturn;
		}

		public bool UpgradeTo (Game game, Tile tile, ref string sError)
		{
			bool	bReturn = false;
			int		nOldRotation;
			Tile	oldTile = this._tile;
			Tile	newTile = tile;

			if (CanUpgradeTo (game, tile, ref sError))
			{
				nOldRotation = this.Rotation;
				this.Rotation = 0;

				if (this.SetValidTileRotation (game, tile, game.CurrentlyOperatingCompany, ref sError))
				{
					oldTile.QuantityLeft++;
					newTile.QuantityLeft--;
					this._tile = tile;

					// Are we upgrading a town or double town to a city?

					if ((this.TownType == eTownType.DblTown) || (this.TownType == eTownType.Town))
					{
						this.TownType = eTownType.City;
						this.MaxTokens = 2;
					}

					TrackSegment.CalculateHexRoutes(this);

					DrawTile ();
					bReturn = true;
				}
				else
				{
					this.Rotation = nOldRotation;
				}
			}

			return bReturn;
		}

		public bool CanDowngradeTo (Game game, Tile tile, ref string sError)
		{
			bool	bReturn = false;

			if (this._tile.ValidDowngrades.Contains (tile.Name))
			{
				bReturn = true;

				if (!game.CanTownsBeUpgradedAndDownGraded)	// See if this is a town that is being Downgraded to a city
				{
					sError = "Can't upgrade or downgrade towns until a six train is bought.";
					bReturn = false;
				}
			}

			return bReturn;
		}

		public bool DowngradeTo (Game game, Tile tile, ref string sError)
		{
			bool	bReturn = false;
			int		nOldRotation;

			if (CanDowngradeTo (game, tile, ref sError))
			{
				nOldRotation = this.Rotation;
				this.Rotation = 0;

				if (this.SetValidTileRotation (game, tile, game.CurrentlyOperatingCompany, ref sError))
				{
					_tile.QuantityLeft++;
					tile.QuantityLeft--;
					this._tile = tile;

					if ((this.TownType == eTownType.DblTown) || (this.TownType == eTownType.Town))
					{
						this.TownType = eTownType.None;	// Town was bulldozed.
					}

					DrawTile ();
					bReturn = true;
				}
				else
				{
					this.Rotation = nOldRotation;
				}
			}

			return bReturn;
		}		
	
		private bool IsValidTile (Game game, Tile tile, ref string sError)  // This routine only does initial tile placement.  Check elsewere for tile upgrades/downgrades.
		{
			bool	bReturn = true;
			string	sIncompatibleTownTypes = "The tile is not compatible with this hex because of incompatible town types.";
			string	sColorNotAvailable = "Currently this tile color is unavailable.";
			string	sInconsistentColorSchema = "Inconsistent color schema.";

			if (_tile == null)	// Does the hex already have a tile?
			{
				if (this.InitialTile.Length > 0)
				{
					if (tile.Name == this.InitialTile)
					{
						bReturn = true;
					}
					else
					{
						bReturn = false;
						sError = "Only tile " + this.InitialTile + " may be laid on this hex.";
					}
				}
				else
				{
					switch (tile.TownType) 
					{
						case WebApplication.Tile.eTileTownType.City:
						{
							if (this.TownType != GameboardHex.eTownType.City)
							{
								sError = sIncompatibleTownTypes;
								bReturn = false;
							}

							break;
						}

						case WebApplication.Tile.eTileTownType.DblTown:
						{
							if (this.TownType != GameboardHex.eTownType.DblTown)
							{
								sError = sIncompatibleTownTypes;
								bReturn = false;
							}
							break;
						}

						case WebApplication.Tile.eTileTownType.Town:
						{
							if (this.TownType != GameboardHex.eTownType.Town)
							{
								sError = sIncompatibleTownTypes;
								bReturn = false;
							}
							break;
						}

						case WebApplication.Tile.eTileTownType.Unpopulated:
						{
							if (this.TownType != GameboardHex.eTownType.None)
							{
								sError = sIncompatibleTownTypes;
								bReturn = false;
							}
							break;
						}
					}
				}

				if (bReturn)	// Now check colors
				{
					switch (tile.Color)
					{
						case WebApplication.Tile.eTileColor.Yellow: 
							bReturn = game.YellowTilesAvailable;

							if (!bReturn)
							{
								sError = sColorNotAvailable;
							}
							else	// Check color versus hex.
							{
								if (this._initialColor != Color.Black)  // Can't lay a yellow tile on a yellow, green, brown or grey hex.  Black indicates no color exists.
								{
									sError = sInconsistentColorSchema;
									bReturn = false;
								}
							}
							break;

						case WebApplication.Tile.eTileColor.Green: 
							bReturn = game.GreenTilesAvailable;

							if (!bReturn)
							{
								sError = sColorNotAvailable;
							}
							else	// Check color versus hex.
							{
								if (this._initialColor != Color.Yellow)  // Can lay a green tile on a yellow hex.  Barrie, London and Kitchner are examples of this.
								{
									sError = sInconsistentColorSchema;
									bReturn = false;
								}
							}
							break;
						case WebApplication.Tile.eTileColor.Brown: 
							bReturn = game.BrownTilesAvailable;

							if (!bReturn)
							{
								sError = sColorNotAvailable;
							}
							else	// Check color versus hex.
							{
								if (this._initialColor != Color.Green)  // No tiles exist for this case in 1856.
								{
									sError = sInconsistentColorSchema;
									bReturn = false;
								}
							}
							break;
						case WebApplication.Tile.eTileColor.Gray:   
							bReturn = game.GrayTilesAvailable;

							if (!bReturn)
							{
								sError = sColorNotAvailable;
							}
							else	// Check color versus hex.
							{
								if (this._initialColor != Color.Brown)  // No tiles exist for this case in 1856.
								{
									sError = sInconsistentColorSchema;
									bReturn = false;
								}
							}
							break;

						default:  // Huh??  Should never get here.
							bReturn = false;
							sError = "Unknown color for tile.";
							break;
					}
				}
			}

			return bReturn;
		}

		private bool RoutesPreserved (Side existingStartSide, SideCollection existingEndSides) 
		{
			bool			bReturn = false;
			SideCollection	newEndSides;
			bool			bFoundEndSide = false;

			foreach (Side newStartSide in this.NewRoutes.Keys)
			{
				if (newStartSide.GetDirection () == existingStartSide.GetDirection ())  // Found the start side.
				{
					bReturn = true;
					newEndSides = this.NewRoutes[newStartSide] as SideCollection;

					foreach (Side existingEndSide in existingEndSides)
					{
						bFoundEndSide = false;

						foreach (Side newEndSide in newEndSides)
						{
							if (newEndSide.GetDirection () == existingEndSide.GetDirection ())
							{
								bFoundEndSide = true;
								break;
							}
						}

						if (!bFoundEndSide)	// One of the end sides was not found therefore not all routes were preserved.
						{
							return false;
						}
					}

					break;
				}
			}

			return bReturn;
		}

		private bool RunOnNewTrack (Game game, Side newStartSide, SideCollection newEndSides)
		{
			bool			bReturn = false;
			HexVisit		hexVisit;
			SideCollection	existingEndSides;
			bool			bFoundExistingStartSide = false;

			// First, see if this company has access to this side.

			hexVisit = game.CurrentlyOperatingCompany.HexVisits[this.Location] as HexVisit;
			bFoundExistingStartSide = false;

			if (hexVisit != null)
			{
				if (hexVisit.VisitedFromThisDirection (newStartSide.GetDirection ()))
				{
					foreach (Side existingStartSide in this.ExistingRoutes.Keys)
					{
						if (existingStartSide.GetDirection () == newStartSide.GetDirection ())
						{
							bFoundExistingStartSide = true;
							existingEndSides = this.ExistingRoutes[existingStartSide] as SideCollection;

							if (newEndSides.Count > existingEndSides.Count)	// Any additional routes?
							{
								bReturn = true;
							}

							break;
						}
					}

					if (!bFoundExistingStartSide)
					{
						bReturn = true;
					}
				}
			}

			return bReturn;
		}

        public bool CanCompanyReachAndHasRouteToToken(PublicCompany operatingCompany)
        {
            bool bReturn = false;

            // First see if the tile connects to existing track for the operating company.

            HexVisit hexVisit;

            hexVisit = operatingCompany.HexVisits[this.Location] as HexVisit;

            if (hexVisit != null)
            {
                if (operatingCompany.DeferredInitialTokenPlacement)	// THB or Erie is laying it's initial tile???
                {
                    bReturn = true;
                }
                else
                {
                    foreach (Side startSide in this.NewRoutes.Keys)
                    {
                        string startDirection = startSide.GetDirection();

                        if (hexVisit.VisitedFromThisDirection(startDirection))
                        {
                            bReturn = true;
                            return bReturn;
                        }
                    }

                    foreach (Side startSide in this.ExistingRoutes.Keys)
                    {
                        string startDirection = startSide.GetDirection();

                        if (hexVisit.VisitedFromThisDirection(startDirection))
                        {
                            bReturn = true;
                            return bReturn;
                        }
                    }                    
                }
            }
            
            return bReturn;
        }


		private bool IsValidRotation (Game game, PublicCompany operatingCompany)	// Is the tile currently in a valid rotation for the currently operating company?  Called during rotation and initial placement of the tile.
		{
			bool	bReturn = false;

			TemporarilyTransferTileRoutesToHex ();

			// First see if the tile connects to existing track for the operating company.

			HexVisit hexVisit;

			hexVisit = operatingCompany.HexVisits[this.Location] as HexVisit;

			if (hexVisit != null)
			{
				if (operatingCompany.DeferredInitialTokenPlacement)	// THB or Erie is laying it's initial tile???
				{
					bReturn = true;
				}
				else
				{
					foreach (Side startSide in this.NewRoutes.Keys)
					{
						string	startDirection = startSide.GetDirection ();

						if (hexVisit.VisitedFromThisDirection (startDirection))
						{
							bReturn = true;
							break;
						}
					}
				}
			}

			// Next see if the tile has any routes to nowhere, i.e. track that runs off the board but not to an red off the board location.

			if (bReturn)	// Only check if the route is already valid.
			{
				foreach (Side startSide in this.NewRoutes.Keys)
				{
					string	startDirection = startSide.GetDirection ();

					if (!this.Neighbors.ContainsKey (startDirection))
					{
						bReturn = false;
						break;
					}
				}
			}

			// Next see if all existing routes are preserved.

			if (bReturn)
			{
				foreach (Side startSide in this.ExistingRoutes.Keys)
				{
					SideCollection	endSides = this.ExistingRoutes[startSide] as SideCollection;

					if (!RoutesPreserved (startSide, endSides))
					{
						bReturn = false;
						break;
					}
				}
			}

			// Finally, can this company run on the new track?

			if (bReturn && this._tile.UpgradeHasNewTrack)
			{
				// There are a few exception cases where there is no new track to run on.  Toronto in 1856 from green to brown and NY in 1830 from green to brown spring to mind.
				// Also, if you are upgrading downgrading a town or double town

				if (operatingCompany.DeferredInitialTokenPlacement)	// THB or Erie is laying it's initial tile???
				{
					bReturn = true;
				}
				else
				{
					if (this.TownType == GameboardHex.eTownType.None)	// Only have to run on new track for unpopulated hexes.
					{
						bReturn = false;

						foreach (Side startSide in this.NewRoutes.Keys)
						{
							SideCollection	endSides = this.NewRoutes[startSide] as SideCollection;

							if (RunOnNewTrack (game, startSide, endSides))
							{
								bReturn = true;
								break;
							}
						}
					}
				}
			}

			return bReturn;
		}

		private bool CitiesNotStillSeperated (Tile oldTile)
		{
			bool	bReturn = false;
			Side	startSide1 = null; 
			Side	startSide2 = null;

			if ((this.Tile != null) && (this.Tile.TileName == "OO") && (this.Tile.Color == WebApplication.Tile.eTileColor.Brown))
			{
				if (this.ExistingRoutes.Keys.Count != 2)  // Only get here if upgrading from green to brown.  Thus, 2 routes in existing and 4 routes in new.
				{
					GameException	e = new GameException ("Illegal number of existing routes for tile 59.");
					throw (e);
				}
				else
				{
					int nCount = 0;

					foreach (Side side in this.ExistingRoutes.Keys)
					{
						if (nCount == 0)
						{
							startSide1 = side;
						}
						else
						{
							startSide2 = side;
						}

						nCount++;
					}
				}

				foreach (Side startSide in this.NewRoutes.Keys)
				{
					foreach (Side endSide in this.NewRoutes[startSide] as SideCollection)
					{
						if ((endSide.GetDirection () == startSide1.GetDirection ()) && (startSide.GetDirection () == startSide2.GetDirection ()) ||
							((endSide.GetDirection () == startSide2.GetDirection ()) && (startSide.GetDirection () == startSide1.GetDirection ())))
						{	// The cities are now connected.  This is illegal.
							bReturn = true;
						}
					}
				}
			}

			return bReturn;
		}

		public bool SetValidTileRotation (Game game, Tile tile, PublicCompany operatingCompany, ref string sError)
		{
			bool	bReturn = true;
			int		nRotations = 0;
			Tile	oldTile;

			oldTile = _tile;  // Save off old tile in case no valid rotations are found.
			_tile = tile;

			while ((!game.ExercisingWaterlooTileLay && !game.ExercisingTheCanadaCompany && !IsValidRotation (game, operatingCompany)) || CitiesNotStillSeperated (oldTile))
			{
				nRotations++;
				this.Rotate ();

				if (nRotations > 6)
				{
					sError = "Can not find valid rotation for tile in this hex.";
					bReturn = false;
					_tile = oldTile;
					break;
				}
			}

			return bReturn;
		}

		public bool InitializeWithTile (Game game, Tile tile, PublicCompany operatingCompany, ref string sError)
		{
			bool	bReturn = false;
			Tile	oldTile = _tile;
			int		nOldRotation = this.Rotation;

			if (IsValidTile (game, tile, ref sError))
			{
				bReturn = SetValidTileRotation (game, tile, operatingCompany, ref sError);

				if (bReturn)
				{
					if (this.Cost > 0)
					{
						if (this.Cost > game.CurrentlyOperatingCompany.Cash)
						{
							sError = "Not enough cash to build on this hex.  It costs $";
							sError += this.Cost + ", company has $" + game.CurrentlyOperatingCompany.Cash;
							bReturn = false;
						}
						else
						{
							game.CurrentlyOperatingCompany.Cash -= this.Cost;		
							game.Bank += this.Cost;
						}
					}

					_tile = tile;
				}
			}

			if (!bReturn)	// Can't initialize with the new tile.  Reset old values.
			{
				_tile = oldTile;
				this.Rotation = nOldRotation;
			}

			return bReturn;
		}

		//[XmlIgnore]  // JWF 10.12.07  Debugging
		public Tile Tile
		{
			get  { return _tile; }
			set { _tile = value; }
		}

		public void Rotate ()
		{
			_nRotation += 60;

			if (_nRotation > 300)
			{
				_nRotation = 0;
			}
		}

		public void DrawTile ()
		{
			string sGif = ".gif";
			string	sFile = "Tiles/";
			string s60 = "_060";
			string s120 = "_120";
			string s180 = "_180";
			string s240 = "_240";
			string s300 = "_300";

			sFile += this.Tile.File;

			switch (this.Rotation)
			{
				case 0:
					sFile = sFile.Substring (0, 10) + sGif;
					break;

				case 60:
					sFile = sFile.Substring (0, 10) + s60 + sGif;
					break;

				case 120:
					sFile = sFile.Substring (0, 10) + s120 + sGif;
					break;

				case 180:
					sFile = sFile.Substring (0, 10) + s180 + sGif;
					break;

				case 240:
					sFile = sFile.Substring (0, 10) + s240 + sGif;
					break;

				case 300:
					sFile = sFile.Substring (0, 10) + s300 + sGif;
					break;
			}

			this.Button.ImageUrl = sFile;
		}

		public int Rotation
		{
			get { return _nRotation; }
			set { _nRotation = value; }
		}

		//[XmlIgnore]  // JWF This is reassigned on every page_load so it doesn't need to be saved?  TODO:  Check this out.
		public ImageButton Button
		{
			get { return _button; }
			set { _button = value; }
		}

		public bool CanLayTile (Game game, ref string sError)
		{
			bool	bReturn = false;

			if (this.PrivateCompanyAtThisHex.Length > 0)	// If a private exists at this hex see if a player owns it.
			{
				foreach (Player player in game.Players)
				{
					foreach (PrivateCompany privateCompany in player.PrivateCompanies)
					{
						if (privateCompany.Name == this.PrivateCompanyAtThisHex)
						{
							sError = "Can't lay track on this hex until " + privateCompany.Name + " is closed or owned by a public company.";
							return false;  // Can't lay tile until the private is sold or closes.
						}
					}
				}
			}
            
			if (m_eHexType == eHexType.Normal)
			{
				bReturn = true;
			}
			else
			{
				sError = "Invalid hex type: "  + m_eHexType.ToString () + " to lay tile on.";
			}

			return bReturn;
		}

		public enum eHexType
		{
			Normal, OffBoard, PassThru
					}

		public enum eTownType
		{
			None, City, Town, DblTown
						}
		
		public enum eHexAttributes
		{
			None = 0, L = 1, Port = 2, Bridge = 4, Tunnel = 8, Private = 16
															   }
		
		// initial values
		private string m_sLocation;
		private int m_nCost;
		private int m_nInitValue;
		private eHexType m_eHexType;
		private eTownType m_eTownType;
		private Hashtable /*MyDictionary<string, string>*/ m_htNeighbors;
		private int m_nMaxTokens;
		private int m_nAttributes;
		private int[] m_nValues;
		private string _privateCompanyAtThisHex;

		public string PrivateCompanyAtThisHex
		{
			get { return _privateCompanyAtThisHex; }
			set { _privateCompanyAtThisHex = value; }
		}

		// runtime values
		public int m_nValue;
		public int m_nNumTokens;
		private bool _portPlacedHere;

		public bool PortPlacedHere 
		{ 
			get { return _portPlacedHere; }
			set { _portPlacedHere = value; }
		}

		public bool CanPlacePortHere ()
		{
			bool	bReturn = false;
			int		nTest = 0;

			nTest = this.Attributes & (int) eHexAttributes.Port;

			if (nTest == (int) eHexAttributes.Port)
			{
				bReturn = true;
			}

			return bReturn;
		}

		//		public string[][] m_sRoutes;
		public string m_sOrientation;

		public string Location
		{
			get { return m_sLocation; }
			set { m_sLocation = value; }
		}

		public Hashtable /*MyDictionary<string, string>*/ Neighbors
		{
			get { return m_htNeighbors; }
		}

		//		public StringCollection ExistingRoutes
		public Hashtable /*MyDictionary<Side, SideCollection>*/ ExistingRoutes
		{
			get { return _existingRoutes; }
		}

		public Hashtable /*MyDictionary<Side, SideCollection>*/ NewRoutes
		{
			get { return _newRoutes; }
		}

		public Color InitialColor
		{
			get { return _initialColor; }
			set { _initialColor = value; }
		}

		public GameboardHex ()	// default constructor needed for serialization
		{
		}

		public GameboardHex (string sLocation)
		{
			_portPlacedHere = false;
			_separateCities = false;		// Only CV will be true, read in from XML config file.
			_initialColor = Color.Black;	// Use black to indicate no initial color.  Toronto, London, Kitchner and a few others will be yellow intially.
			_existingRoutes = new Hashtable /*MyDictionary<Side, SideCollection>*/();
			_newRoutes = new Hashtable /*MyDictionary<Side, SideCollection>*/();
			_button = null;
			_tile = null;
			_nRotation = 0;
			_privateCompanyAtThisHex = "";
			_city = "";
			m_sLocation		= sLocation;
			m_nCost			= 0;
			m_nInitValue	= 0;
			m_eHexType		= eHexType.Normal;
			m_eTownType		= eTownType.None;
			m_nAttributes	= 0;
			m_nMaxTokens	= 0;
			m_nValues		= new int[4];
			m_htNeighbors = new Hashtable /*MyDictionary<string, string>*/();

			m_nValue		= 0;
			m_nNumTokens	= 0;
			_tokens = new TokenCollection ();
			this.InitialTile = "";
			_values = "";
		}

		public int Cost
		{
			get	{ return m_nCost; }
			set { m_nCost = value; }
		}

		public bool BridgeHere
		{
			get 
			{
				bool	bReturn = false;

				if ((this.Attributes & (int) eHexAttributes.Bridge) > 0)
				{
					bReturn = true;
				}

				return bReturn;
			}
		}

		public bool TunnelHere
		{
			get 
			{
				bool	bReturn = false;

				if ((this.Attributes & (int) eHexAttributes.Tunnel) > 0)
				{
					bReturn = true;
				}

				return bReturn;
			}
		}

		//[XmlIgnore]  // Should be ok as it's calculated.  TODO  Jeff test this out.
		public int Value
		{
			get	
			{ 
				int		nValue = m_nValue;

				if (this.Tile != null)
				{
					nValue = Tile.Worth;
				}
				else 
				{
					if (m_nValue == 0)	// Use the initial value only if the value hasn't been set.
					{
						if (this.InitValue > 0)
						{
							nValue = this.InitValue;
						}
					}
				}

				if (this.PortPlacedHere && (Game.CurrentlyOperatingCompany != null) && Game.CurrentlyOperatingCompany.PortRights)
				{
					nValue += 20;
				}

				if (this.BridgeHere && (Game.CurrentlyOperatingCompany != null) && Game.CurrentlyOperatingCompany.BridgeRights)
				{
					nValue += 10;
				}

				if (this.TunnelHere && (Game.CurrentlyOperatingCompany != null) && Game.CurrentlyOperatingCompany.TunnelRights)
				{
					nValue += 10;
				}

				return nValue; 
			}

			set { m_nValue = value; }
		}
	

		public int InitValue 
		{
			get	{ return m_nInitValue; }
			set { m_nInitValue = value; }
		}
	
		public int MaxTokens
		{
			get	{ return m_nMaxTokens; }
			set { m_nMaxTokens = value; }
		}
	
		public eHexType HexType
		{
			get	{ return m_eHexType; }
			set { m_eHexType = value; }
		}
	
		public eTownType TownType
		{
			get	{ return m_eTownType; }
			set { m_eTownType = value; }
		}
	
		public int Attributes
		{
			get	{ return m_nAttributes; }
			set { m_nAttributes = value; }
		}
	
		public void AddNeighbors(string sSide, string sHex)
		{
			m_htNeighbors.Add(sSide, sHex);	
		}

		public void TransferTileRoutesToHex ()
		{
			if (this.Tile != null)
			{
				this.ExistingRoutes.Clear ();

				foreach (Side startSide in this.Tile.Routes.Keys)
				{
					Side			newStartSide = new Side ();
					SideCollection  newEndSides = new SideCollection ();
					SideCollection endSides = this.Tile.Routes[startSide] as SideCollection;

					// Take into account current rotation and changing from A-F.
					newStartSide.ConvertToCompassWithRotation (startSide, this.Rotation);

					foreach (Side endSide in endSides)
					{
						Side	newEndSide = new Side ();
						newEndSide.ConvertToCompassWithRotation (endSide, this.Rotation);
						newEndSides.Add (newEndSide);
					}

					this.ExistingRoutes.Add (newStartSide, newEndSides);
				}
			}
		}

		public void TemporarilyTransferTileRoutesToHex ()
		{
			if (this.Tile != null)
			{
				this.NewRoutes.Clear ();

				foreach (Side startSide in this.Tile.Routes.Keys)
				{
					Side			newStartSide = new Side ();
					SideCollection  newEndSides = new SideCollection ();
					SideCollection endSides = this.Tile.Routes[startSide] as SideCollection;

					// Take into account current rotation and changing from A-F.
					newStartSide.ConvertToCompassWithRotation (startSide, this.Rotation);

					foreach (Side endSide in endSides)
					{
						Side	newEndSide = new Side ();
						newEndSide.ConvertToCompassWithRotation (endSide, this.Rotation);
						newEndSides.Add (newEndSide);
					}

					this.NewRoutes.Add (newStartSide, newEndSides);
				}
			}
		}

		public void ComputeGreenBrownSingleCityTokenOffset (int nCount, ref int nLeft, ref int nTop)
		{
			switch (this.Rotation)
			{
				case 0:
					if (nCount == 1)
					{
						nLeft -= Token.tokenWidth / 2;
					}
					else
					{
						nLeft += Token.tokenWidth / 2;
					}
					break;

				case 60:
					if (nCount == 1)
					{
						nLeft -= Token.tokenWidth / 3 + 1;
						nTop -= Token.tokenHeight / 3;
					}
					else
					{
						nLeft += Token.tokenWidth / 3 - 1;
						nTop += Token.tokenHeight / 3;
					}
					break;

				case 120:
					if (nCount == 1)
					{
						nLeft += Token.tokenWidth / 3 - 1;
						nTop -= Token.tokenHeight / 3;
					}
					else
					{
						nLeft -= Token.tokenWidth / 3 + 1;
						nTop += Token.tokenHeight / 3;
					}
					break;

				case 180:
					if (nCount == 1)
					{
						nLeft += Token.tokenWidth / 2;
					}
					else
					{
						nLeft -= Token.tokenWidth / 2;
					}
					break;

				case 240:
					if (nCount == 1)
					{
						nLeft += Token.tokenWidth / 3 - 1;
						nTop += Token.tokenHeight / 3;
					}
					else
					{
						nLeft -= Token.tokenWidth / 3 + 1;
						nTop -= Token.tokenHeight / 3;
					}
					break;

				case 300:
					if (nCount == 1)
					{
						nLeft -= Token.tokenWidth / 3 + 1;
						nTop += Token.tokenHeight / 3;
					}
					else
					{
						nLeft += Token.tokenWidth / 3 - 1;
						nTop -= Token.tokenHeight / 3;
					}
					break;

				default:
					GameException	e = new GameException ("Illegal rotation.");
					throw (e);
			}
		}

		public bool CanLayTokenOnThisSide (Game game, Side tokenSide)
		{
			bool	bReturn = false;

			// Is there track on this side?  Is this check needed anymore?

			foreach (Side startSide in this.ExistingRoutes.Keys)
			{
				if (startSide.GetDirection () == tokenSide.GetDirection ())
				{
					bReturn = true;
					break;
				}
			}

			// Is there already a token on this side?

			if (bReturn)
			{
				foreach (Token existingToken in this.Tokens)
				{
					if (existingToken.LocationInHex.GetDirection () == tokenSide.GetDirection ())
					{
						bReturn = false;
						break;
					}
				}
			}

			// Can the company reach this side?

			if (bReturn && !game.ExercisingWaterlooTokenPlacement)
			{
				if (game.CurrentlyOperatingCompany.HexVisits.ContainsKey (this.Location))
				{
					HexVisit hexVisit = game.CurrentlyOperatingCompany.HexVisits[this.Location] as HexVisit; 

					if (!hexVisit.VisitedFromThisDirection (tokenSide.GetDirection ()))
					{
						bReturn = false;  // Didn't visit from the start side, did they visit from the end side?

						// Now check if the company visited from the end of this route.

						foreach (Side startSide in this.ExistingRoutes.Keys)
						{
							if (startSide.GetDirection () == tokenSide.GetDirection ())
							{
								foreach (Side endSide in this.ExistingRoutes[startSide] as SideCollection)
								{
									if (hexVisit.VisitedFromThisDirection (endSide.GetDirection ()))
									{
										bReturn = true;
										break;
									}
								}

								break;
							}
						}
					}
				}
				else
				{
					bReturn = false;
				}
			}

			return bReturn;
		}

		private void GetSeperateCityTokenLocationTile59 (ref int nLeft, ref int nTop, Side tokenSide)
		{
			switch (tokenSide.GetDirection ())
			{
				case "N":
				{
					if (this.Rotation == 120)
					{
						nLeft += 40;
						nTop += 10;
					}
					else if (this.Rotation == 240)
					{
						nLeft += 20;
						nTop += 10;
					}
					else
					{
						GameException e = new GameException ("Token side rotation mismatch");
						throw (e);
					}

					break;
				}

				case "NE":
				{
					if (this.Rotation == 180)
					{
						nLeft += 50;
						nTop += 24;
					}
					else if (this.Rotation == 300)
					{
						nLeft += 40;
						nTop += 8;
					}
					else
					{
						GameException e = new GameException ("Token side rotation mismatch");
						throw (e);
					}

					break;
				}

				case "SE":
				{
					if (this.Rotation == 0)
					{
						nLeft += 50;
						nTop += 24;
					}
					else if (this.Rotation == 240)
					{
						nLeft += 40;
						nTop += 43;
					}
					else
					{
						GameException e = new GameException ("Token side rotation mismatch");
						throw (e);
					}

					break;
				}

				case "S":
				{
					if (this.Rotation == 60)
					{
						nLeft += 40;
						nTop += 42;
					}
					else if (this.Rotation == 300)
					{
						nLeft += 20;
						nTop += 43;
					}
					else
					{
						GameException e = new GameException ("Token side rotation mismatch");
						throw (e);
					}

					break;
				}

				case "SW":
				{
					if (this.Rotation == 0)
					{
						nLeft += 12;
						nTop += 24;
					}
					else if (this.Rotation == 120)
					{
						nLeft += 20;
						nTop += 43;
					}
					else
					{
						GameException e = new GameException ("Token side rotation mismatch");
						throw (e);
					}

					break;
				}
				case "NW":
				{
					if (this.Rotation == 60)
					{
						nLeft += 18;
						nTop += 10;
					}
					else if (this.Rotation == 180)
					{
						nLeft += 10;
						nTop += 24;
					}
					else
					{
						GameException e = new GameException ("Token side rotation mismatch");
						throw (e);
					}

					break;
				}

				default:
					GameException	illegalDirectionException = new GameException ("Illegal direction for token side.");
					throw (illegalDirectionException);
			}
		}

		private void GetSeperateCityTokenLocationTile64 (ref int nLeft, ref int nTop, Side tokenSide)
		{
			switch (this.Rotation)
			{
				case 0:
				{
					if ((tokenSide.GetDirection () == "S") || (tokenSide.GetDirection () == "NE"))
					{
						nLeft += 42;
						nTop += 30;
					}
					else if ((tokenSide.GetDirection () == "SW") || (tokenSide.GetDirection () == "NW"))
					{
						nLeft += 10;
						nTop += 24;
					}
					else
					{
						GameException	e = new GameException ("Illegal direction for this rotation, tile 64.");
						throw (e);
					}

					break;
				}

				case 60:
				{
					if ((tokenSide.GetDirection () == "NW") || (tokenSide.GetDirection () == "N"))
					{
						nLeft += 20;
						nTop += 10;
					}
					else if ((tokenSide.GetDirection () == "SW") || (tokenSide.GetDirection () == "SE"))
					{
						nLeft += 30;
						nTop += 40;
					}
					else
					{
						GameException	e = new GameException ("Illegal direction for this rotation, tile 64.");
						throw (e);
					}

					break;
				}

				case 120:
				{
					if ((tokenSide.GetDirection () == "S") || (tokenSide.GetDirection () == "NW"))
					{
						nLeft+= 17;
						nTop += 32;
					}
					else if ((tokenSide.GetDirection () == "N") || (tokenSide.GetDirection () == "NE"))
					{
						nLeft += 40;
						nTop += 8;
					}
					else
					{
						GameException	e = new GameException ("Illegal direction for this rotation, tile 64.");
						throw (e);
					}

					break;
				}

				case 180:
				{
					if ((tokenSide.GetDirection () == "SW") || (tokenSide.GetDirection () == "N"))
					{
						nLeft += 18;
						nTop += 20;
					}
					else if ((tokenSide.GetDirection () == "NE") || (tokenSide.GetDirection () == "SE"))
					{
						nLeft += 50;
						nTop += 26;
					}
					else
					{
						GameException	e = new GameException ("Illegal direction for this rotation, tile 64.");
						throw (e);
					}

					break;
				}

				case 240:
				{
					if ((tokenSide.GetDirection () == "NW") || (tokenSide.GetDirection () == "NE"))
					{
						nLeft += 30;
						nTop += 12;
					}
					else if ((tokenSide.GetDirection () == "S") || (tokenSide.GetDirection () == "SE"))
					{
						nLeft += 40;
						nTop += 44;
					}
					else
					{
						GameException	e = new GameException ("Illegal direction for this rotation, tile 64.");
						throw (e);
					}

					break;
				}

				case 300:
				{
					if ((tokenSide.GetDirection () == "N") || (tokenSide.GetDirection () == "SE"))
					{
						nLeft += 40;
						nTop += 20;
					}
					else if ((tokenSide.GetDirection () == "S") || (tokenSide.GetDirection () == "SW"))
					{
						nLeft += 20;
						nTop += 44;
					}
					else
					{
						GameException	e = new GameException ("Illegal direction for this rotation, tile 64.");
						throw (e);
					}

					break;
				}

				default:
					GameException	illegalRotationException = new GameException ("Illegal rotation.");
					throw (illegalRotationException);
			}
		}

		private void GetSeperateCityTokenLocationTile65 (ref int nLeft, ref int nTop, Side tokenSide)
		{
			switch (this.Rotation)
			{
				case 0:
					if ((tokenSide.GetDirection () == "NW") || (tokenSide.GetDirection () == "N"))
					{
						nLeft += 20;
						nTop += 9;
					}
					else if ((tokenSide.GetDirection () == "S") || (tokenSide.GetDirection () == "NE"))
					{
						nLeft += 40;
						nTop += 31;
					}
					else
					{
						GameException	e = new GameException ("Illegal direction for this rotation, tile 65.");
						throw (e);
					}

					break;

				case 60:
					if ((tokenSide.GetDirection () == "SW") || (tokenSide.GetDirection () == "SE"))
					{
						nLeft += 30;
						nTop += 40;
					}
					else if ((tokenSide.GetDirection () == "N") || (tokenSide.GetDirection () == "NE"))
					{
						nLeft += 40;
						nTop += 9;
					}
					else
					{
						GameException	e = new GameException ("Illegal direction for this rotation, tile 65.");
						throw (e);
					}

					break;

				case 120:
					if ((tokenSide.GetDirection () == "NW") || (tokenSide.GetDirection () == "S"))
					{
						nLeft+= 18;
						nTop += 32;
					}
					else if ((tokenSide.GetDirection () == "NE") || (tokenSide.GetDirection () == "SE"))
					{
						nLeft += 50;
						nTop += 26;
					}
					else
					{
						GameException	e = new GameException ("Illegal direction for this rotation, tile 65.");
						throw (e);
					}

					break;

				case 180:
					if ((tokenSide.GetDirection () == "SW") || (tokenSide.GetDirection () == "N"))
					{
						nLeft += 18;
						nTop += 20;
					}
					else if ((tokenSide.GetDirection () == "S") || (tokenSide.GetDirection () == "SE"))
					{
						nLeft += 40;
						nTop += 42;
					}
					else
					{
						GameException	e = new GameException ("Illegal direction for this rotation, tile 65.");
						throw (e);
					}

					break;

				case 240:
					if ((tokenSide.GetDirection () == "SW") || (tokenSide.GetDirection () == "S"))
					{
						nLeft += 20;
						nTop += 42;
					}
					else if ((tokenSide.GetDirection () == "NW") || (tokenSide.GetDirection () == "NE"))
					{
						nLeft += 30;
						nTop += 12;
					}
					else
					{
						GameException	e = new GameException ("Illegal direction for this rotation, tile 65.");
						throw (e);
					}
					break;

				case 300:
					if ((tokenSide.GetDirection () == "SW") || (tokenSide.GetDirection () == "NW"))
					{
						nLeft += 10;
						nTop += 26;
					}
					else if ((tokenSide.GetDirection () == "N") || (tokenSide.GetDirection () == "SE"))
					{
						nLeft += 41;
						nTop += 20;
					}
					else
					{
						GameException	e = new GameException ("Illegal direction for this rotation, tile 65.");
						throw (e);
					}

					break;

				default:
					GameException	illegalRotationException = new GameException ("Illegal rotation.");
					throw (illegalRotationException);
			}
		}

		private void GetSeperateCityTokenLocationTile66 (ref int nLeft, ref int nTop, Side tokenSide)
		{
			switch (this.Rotation)
			{
				case 0:
					if ((tokenSide.GetDirection () == "NW") || (tokenSide.GetDirection () == "N"))
					{
						nLeft += 20;
						nTop += 10;
					}
					else if ((tokenSide.GetDirection () == "SW") || (tokenSide.GetDirection () == "NE"))
					{
						nLeft += 45;
						nTop += 18;
					}
					else
					{
						GameException	e = new GameException ("Illegal direction for this rotation, tile 66.");
						throw (e);
					}

					break;

				case 60:
					if ((tokenSide.GetDirection () == "N") || (tokenSide.GetDirection () == "NE"))
					{
						nLeft += 40;
						nTop += 9;
					}
					else if ((tokenSide.GetDirection () == "NW") || (tokenSide.GetDirection () == "SE"))
					{
						nLeft += 45;
						nTop += 34;
					}
					else
					{
						GameException	e = new GameException ("Illegal direction for this rotation, tile 66.");
						throw (e);
					}

					break;

				case 120:
					if ((tokenSide.GetDirection () == "S") || (tokenSide.GetDirection () == "N"))
					{
						nLeft+= 30;
						nTop += 42;
					}
					else if ((tokenSide.GetDirection () == "NE") || (tokenSide.GetDirection () == "SE"))
					{
						nLeft += 50;
						nTop += 26;
					}
					else
					{
						GameException	e = new GameException ("Illegal direction for this rotation, tile 66.");
						throw (e);
					}

					break;

				case 180:
					if ((tokenSide.GetDirection () == "SW") || (tokenSide.GetDirection () == "NE"))
					{
						nLeft += 15;
						nTop += 34;
					}
					else if ((tokenSide.GetDirection () == "S") || (tokenSide.GetDirection () == "SE"))
					{
						nLeft += 40;
						nTop += 43;
					}
					else
					{
						GameException	e = new GameException ("Illegal direction for this rotation, tile 66.");
						throw (e);
					}

					break;

				case 240:
					if ((tokenSide.GetDirection () == "NW") || (tokenSide.GetDirection () == "SE"))
					{
						nLeft += 15;
						nTop += 18;
					}
					else if ((tokenSide.GetDirection () == "SW") || (tokenSide.GetDirection () == "S"))
					{
						nLeft += 20;
						nTop += 43;
					}
					else
					{
						GameException	e = new GameException ("Illegal direction for this rotation, tile 66.");
						throw (e);
					}
					break;

				case 300:
					if ((tokenSide.GetDirection () == "SW") || (tokenSide.GetDirection () == "NW"))
					{
						nLeft += 9;
						nTop += 26;
					}
					else if ((tokenSide.GetDirection () == "S") || (tokenSide.GetDirection () == "N"))
					{
						nLeft += 30;
						nTop += 9;
					}
					else
					{
						GameException	e = new GameException ("Illegal direction for this rotation, tile 66.");
						throw (e);
					}

					break;

				default:
					GameException	illegalRotationException = new GameException ("Illegal rotation.");
					throw (illegalRotationException);
			}
		}

		private void GetSeperateCityTokenLocationTile67 (ref int nLeft, ref int nTop, Side tokenSide)
		{
			switch (this.Rotation)
			{
				case 0:
					if ((tokenSide.GetDirection () == "N") || (tokenSide.GetDirection () == "S"))
					{
						nLeft += 30;
						nTop += 9;
					}
					else if ((tokenSide.GetDirection () == "SW") || (tokenSide.GetDirection () == "SE"))
					{
						nLeft += 15;
						nTop += 37;
					}
					else
					{
						GameException	e = new GameException ("Illegal direction for this rotation, tile 67.");
						throw (e);
					}

					break;

				case 60:
					if ((tokenSide.GetDirection () == "NW") || (tokenSide.GetDirection () == "S"))
					{
						nLeft += 12;
						nTop += 18;
					}
					else if ((tokenSide.GetDirection () == "SW") || (tokenSide.GetDirection () == "NE"))
					{
						nLeft += 45;
						nTop += 19;
					}
					else
					{
						GameException	e = new GameException ("Illegal direction for this rotation, tile 67.");
						throw (e);
					}

					break;

				case 120:
					if ((tokenSide.GetDirection () == "SW") || (tokenSide.GetDirection () == "N"))
					{
						nLeft+= 28;
						nTop += 7;
					}
					else if ((tokenSide.GetDirection () == "NW") || (tokenSide.GetDirection () == "SE"))
					{
						nLeft += 45;
						nTop += 34;
					}
					else
					{
						GameException	e = new GameException ("Illegal direction for this rotation, tile 67.");
						throw (e);
					}

					break;

				case 180:
					if ((tokenSide.GetDirection () == "NW") || (tokenSide.GetDirection () == "NE"))
					{
						nLeft += 45;
						nTop += 14;
					}
					else if ((tokenSide.GetDirection () == "N") || (tokenSide.GetDirection () == "S"))
					{
						nLeft += 30;
						nTop += 43;
					}
					else
					{
						GameException	e = new GameException ("Illegal direction for this rotation, tile 67.");
						throw (e);
					}

					break;

				case 240:
					if ((tokenSide.GetDirection () == "SW") || (tokenSide.GetDirection () == "NE"))
					{
						nLeft += 15;
						nTop += 33;
					}
					else if ((tokenSide.GetDirection () == "N") || (tokenSide.GetDirection () == "SE"))
					{
						nLeft += 46;
						nTop += 34;
					}
					else
					{
						GameException	e = new GameException ("Illegal direction for this rotation, tile 67.");
						throw (e);
					}
					break;

				case 300:
					if ((tokenSide.GetDirection () == "NW") || (tokenSide.GetDirection () == "SE"))
					{
						nLeft += 15;
						nTop += 18;
					}
					else if ((tokenSide.GetDirection () == "S") || (tokenSide.GetDirection () == "NE"))
					{
						nLeft += 31;
						nTop += 44;
					}
					else
					{
						GameException	e = new GameException ("Illegal direction for this rotation, tile 67.");
						throw (e);
					}

					break;

				default:
					GameException	illegalRotationException = new GameException ("Illegal rotation.");
					throw (illegalRotationException);
			}
		}

		private void GetSeperateCityTokenLocationTile68 (ref int nLeft, ref int nTop, Side tokenSide)
		{
			switch (this.Rotation)
			{
				case 0:
					if ((tokenSide.GetDirection () == "NW") || (tokenSide.GetDirection () == "SE"))
					{
						nLeft += 15;
						nTop += 18;
					}
					else if ((tokenSide.GetDirection () == "N") || (tokenSide.GetDirection () == "S"))
					{
						nLeft += 29;
						nTop += 42;
					}
					else
					{
						GameException	e = new GameException ("Illegal direction for this rotation, tile 68.");
						throw (e);
					}

					break;

				case 60:
					if ((tokenSide.GetDirection () == "N") || (tokenSide.GetDirection () == "S"))
					{
						nLeft += 29;
						nTop += 9;
					}
					else if ((tokenSide.GetDirection () == "SW") || (tokenSide.GetDirection () == "NE"))
					{
						nLeft += 15;
						nTop += 34;
					}
					else
					{
						GameException	e = new GameException ("Illegal direction for this rotation, tile 68.");
						throw (e);
					}

					break;

				case 120:
					if ((tokenSide.GetDirection () == "NW") || (tokenSide.GetDirection () == "SE"))
					{
						nLeft+= 14;
						nTop += 18;
					}
					else if ((tokenSide.GetDirection () == "SW") || (tokenSide.GetDirection () == "NE"))
					{
						nLeft += 44;
						nTop += 18;
					}
					else
					{
						GameException	e = new GameException ("Illegal direction for this rotation, tile 68.");
						throw (e);
					}

					break;

				case 180:
					if ((tokenSide.GetDirection () == "N") || (tokenSide.GetDirection () == "S"))
					{
						nLeft += 29;
						nTop += 9;
					}
					else if ((tokenSide.GetDirection () == "NW") || (tokenSide.GetDirection () == "SE"))
					{
						nLeft += 45;
						nTop += 34;
					}
					else
					{
						GameException	e = new GameException ("Illegal direction for this rotation, tile 68.");
						throw (e);
					}

					break;

				case 240:
					if ((tokenSide.GetDirection () == "N") || (tokenSide.GetDirection () == "S"))
					{
						nLeft += 29;
						nTop += 43;
					}
					else if ((tokenSide.GetDirection () == "SW") || (tokenSide.GetDirection () == "NE"))
					{
						nLeft += 44;
						nTop += 17;
					}
					else
					{
						GameException	e = new GameException ("Illegal direction for this rotation, tile 68.");
						throw (e);
					}
					break;

				case 300:
					if ((tokenSide.GetDirection () == "SW") || (tokenSide.GetDirection () == "NE"))
					{
						nLeft += 15;
						nTop += 34;
					}
					else if ((tokenSide.GetDirection () == "NW") || (tokenSide.GetDirection () == "SE"))
					{
						nLeft += 45;
						nTop += 34;
					}
					else
					{
						GameException	e = new GameException ("Illegal direction for this rotation, tile 68.");
						throw (e);
					}

					break;

				default:
					GameException	illegalRotationException = new GameException ("Illegal rotation.");
					throw (illegalRotationException);
			}
		}

		private void GetSeperateCityTokenLocationTile120 (ref int nLeft, ref int nTop, Side tokenSide)
		{
			if ((tokenSide.GetDirection () == "SW") || (tokenSide.GetDirection () == "NW"))
			{
				nLeft += 10;
				nTop += 24;
			}
			else if ((tokenSide.GetDirection () == "N") || (tokenSide.GetDirection () == "NE"))
			{
				nLeft += 39;
				nTop += 7;
			}
			else 
			{
				GameException	illegalDirectionException = new GameException ("Illegal direction for token side.");
				throw (illegalDirectionException);
			}
		}

		private void GetSeperateCityTokenLocationTile122 (ref int nLeft, ref int nTop, Side tokenSide)
		{
			if (tokenSide.GetDirection () == "SW")
			{
				nLeft += 19;
				nTop += 43;
			}
			else if (tokenSide.GetDirection () == "NW")
			{
				nLeft += 12;
				nTop += 23;
			}
			else if (tokenSide.GetDirection () == "N")
			{
				nLeft += 41;
				nTop += 7;
			}
			else if (tokenSide.GetDirection () == "NE")
			{
				nLeft += 50;
				nTop += 27;
			}
			else 
			{
				GameException	illegalDirectionException = new GameException ("Illegal direction for token side.");
				throw (illegalDirectionException);
			}
		}

		private void GetSeperateCityTokenLocationTile124 (ref int nLeft, ref int nTop, Side tokenSide)
		{
			if (tokenSide.GetDirection () == "SW")
			{
				nLeft += 26;
				nTop += 41;
			}
			else if (tokenSide.GetDirection () == "NW")
			{
				nLeft += 18;
				nTop += 24;
			}
			else if (tokenSide.GetDirection () == "N")
			{
				nLeft += 35;
				nTop += 11;
			}
			else if (tokenSide.GetDirection () == "NE")
			{
				nLeft += 44;
				nTop += 29;
			}
			else 
			{
				GameException	illegalDirectionException = new GameException ("Illegal direction for token side.");
				throw (illegalDirectionException);
			}
		}

		public void GetSeperateCityTokenLocation (int nCount, ref int nLeft, ref int nTop, Side tokenSide)
		{
			if (_tile == null)
			{
				if (this.City == "Toronto")
				{
					if (tokenSide.GetDirection () == "NE")
					{
						nLeft += 48;
						nTop += 24;
					}
					else if (tokenSide.GetDirection () == "SW")
					{
						nLeft += 8;
						nTop += 24;
					}
				}
			}
			else
			{
				switch (_tile.Name)
				{
					case "59":
					{
						GetSeperateCityTokenLocationTile59 (ref nLeft, ref nTop, tokenSide);
						break;
					}

					case "64":
					{
						GetSeperateCityTokenLocationTile64 (ref nLeft, ref nTop, tokenSide);
						break;
					}

					case "65":
					{
						GetSeperateCityTokenLocationTile65 (ref nLeft, ref nTop, tokenSide);
						break;
					}

					case "66":
					{
						GetSeperateCityTokenLocationTile66 (ref nLeft, ref nTop, tokenSide);
						break;
					}

					case "67":
					{
						GetSeperateCityTokenLocationTile67 (ref nLeft, ref nTop, tokenSide);
						break;
					}

					case "68":
					{
						GetSeperateCityTokenLocationTile68 (ref nLeft, ref nTop, tokenSide);
						break;
					}

					case "120":
					{
						GetSeperateCityTokenLocationTile120 (ref nLeft, ref nTop, tokenSide);
						break;
					}

					case "122":
					{
						GetSeperateCityTokenLocationTile122 (ref nLeft, ref nTop, tokenSide);
						break;
					}

					case "123":
					{
						switch (nCount)
						{
							case 1:
								nLeft += 19;
								nTop += 32;
								break;

							case 2:
								nLeft += 30;
								nTop += 14;
								break;

							case 3:
								nLeft += 41;
								nTop += 32;
								break;

							default:
								GameException	e = new GameException ("Too many tokens, max is 3 in Hamilton");
								throw (e);
						}

						break;
					}

					case "124":
					{
						GetSeperateCityTokenLocationTile124 (ref nLeft, ref nTop, tokenSide);
						break;
					}

					default:
						GameException	exceptionTileNotFound = new GameException ("Tile not found.");
						throw (exceptionTileNotFound);
				}
			}
		}


		public bool SetSideFromTileCoordinatesTile59 (int nX, int nY, ref Side tokenSide)
		{
			Point		pointToHitTest = new Point (nX, nY);
			Rectangle	testRectangle;

			switch (this.Rotation)
			{
				case 0:
				{
					testRectangle = new Rectangle (8, 26, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("SW");
						return true;
					}

					testRectangle = new Rectangle (49, 26, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("SE");
						return true;
					}

					return false;
				}

				case 60:
				{
					testRectangle = new Rectangle (19, 7, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("NW");
						return true;
					}

					testRectangle = new Rectangle (39, 42, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("S");
						return true;
					}

					return false;
				}

				case 120:
				{
					testRectangle = new Rectangle (39, 8, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("N");
						return true;
					}

					testRectangle = new Rectangle (19, 41, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("SW");
						return true;
					}

					return false;
				}

				case 180:
				{
					testRectangle = new Rectangle (8, 24, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("NW");
						return true;
					}

					testRectangle = new Rectangle (49, 24, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("NE");
						return true;
					}

					return false;
				}

				case 240:
				{
					testRectangle = new Rectangle (18, 8, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("N");
						return true;
					}

					testRectangle = new Rectangle (38, 42, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("SE");
						return true;
					}

					return false;
				}

				case 300:
				{
					testRectangle = new Rectangle (19, 41, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("S");
						return true;
					}

					testRectangle = new Rectangle (39, 8, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("NE");
						return true;
					}

					return false;
				}

				default:
					GameException	illegalRotationException = new GameException ("Illegal rotation.");
					throw (illegalRotationException);
			}
		}

		public bool SetSideFromTileCoordinatesTile64 (int nX, int nY, ref Side tokenSide)
		{
			Point		pointToHitTest = new Point (nX, nY);
			Rectangle	testRectangle;

			switch (this.Rotation)
			{
				case 0:
				{
					testRectangle = new Rectangle (8, 26, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("SW");
						return true;
					}

					testRectangle = new Rectangle (40, 30, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("S");
						return true;
					}

					return false;
				}

				case 60:
				{
					testRectangle = new Rectangle (19, 7, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("N");
						return true;
					}

					testRectangle = new Rectangle (29, 37, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("SE");
						return true;
					}

					return false;
				}

				case 120:
				{
					testRectangle = new Rectangle (16, 30, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("S");
						return true;
					}

					testRectangle = new Rectangle (39, 8, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("N");
						return true;
					}

					return false;
				}

				case 180:
				{
					testRectangle = new Rectangle (17, 19, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("N");
						return true;
					}

					testRectangle = new Rectangle (49, 24, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("NE");
						return true;
					}

					return false;
				}

				case 240:
				{
					testRectangle = new Rectangle (29, 10, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("NE");
						return true;
					}

					testRectangle = new Rectangle (38, 42, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("S");
						return true;
					}

					return false;
				}

				case 300:
				{
					testRectangle = new Rectangle (19, 41, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("S");
						return true;
					}

					testRectangle = new Rectangle (39, 18, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("N");
						return true;
					}

					return false;
				}

				default:
					GameException	illegalRotationException = new GameException ("Illegal rotation.");
					throw (illegalRotationException);
			}
		}

		public bool SetSideFromTileCoordinatesTile65 (int nX, int nY, ref Side tokenSide)
		{
			Point		pointToHitTest = new Point (nX, nY);
			Rectangle	testRectangle;

			switch (this.Rotation)
			{
				case 0:
				{
					testRectangle = new Rectangle (19, 8, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("N");
						return true;
					}

					testRectangle = new Rectangle (40, 30, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("S");
						return true;
					}

					return false;
				}

				case 60:
				{
					testRectangle = new Rectangle (39, 8, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("N");
						return true;
					}

					testRectangle = new Rectangle (29, 37, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("SW");
						return true;
					}

					return false;
				}

				case 120:
				{
					testRectangle = new Rectangle (17, 30, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("S");
						return true;
					}

					testRectangle = new Rectangle (49, 24, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("NE");
						return true;
					}

					return false;
				}

				case 180:
				{
					testRectangle = new Rectangle (17, 18, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("N");
						return true;
					}

					testRectangle = new Rectangle (38, 41, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("S");
						return true;
					}

					return false;
				}

				case 240:
				{
					testRectangle = new Rectangle (19, 42, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("S");
						return true;
					}

					testRectangle = new Rectangle (29, 11, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("NE");
						return true;
					}

					return false;
				}

				case 300:
				{
					testRectangle = new Rectangle (9, 25, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("SW");
						return true;
					}

					testRectangle = new Rectangle (39, 18, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("N");
						return true;
					}

					return false;
				}

				default:
					GameException	illegalRotationException = new GameException ("Illegal rotation.");
					throw (illegalRotationException);
			}
		}

		public bool SetSideFromTileCoordinatesTile66 (int nX, int nY, ref Side tokenSide)
		{
			Point		pointToHitTest = new Point (nX, nY);
			Rectangle	testRectangle;

			switch (this.Rotation)
			{
				case 0:
				{
					testRectangle = new Rectangle (16, 6, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("N");
						return true;
					}

					testRectangle = new Rectangle (44, 17, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("NE");
						return true;
					}

					return false;
				}

				case 60:
				{
					testRectangle = new Rectangle (37, 5, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("N");
						return true;
					}

					testRectangle = new Rectangle (44, 34, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("SE");
						return true;
					}

					return false;
				}

				case 120:
				{
					testRectangle = new Rectangle (27, 44, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("S");
						return true;
					}

					testRectangle = new Rectangle (51, 23, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("SE");
						return true;
					}

					return false;
				}

				case 180:
				{
					testRectangle = new Rectangle (12, 30, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("SW");
						return true;
					}

					testRectangle = new Rectangle (40, 43, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("S");
						return true;
					}

					return false;
				}

				case 240:
				{
					testRectangle = new Rectangle (19, 44, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("S");
						return true;
					}

					testRectangle = new Rectangle (14, 14, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("SE");
						return true;
					}

					return false;
				}

				case 300:
				{
					testRectangle = new Rectangle (8, 24, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("SW");
						return true;
					}

					testRectangle = new Rectangle (31, 5, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("N");
						return true;
					}

					return false;
				}

				default:
					GameException	illegalRotationException = new GameException ("Illegal rotation.");
					throw (illegalRotationException);
			}
		}

		public bool SetSideFromTileCoordinatesTile67 (int nX, int nY, ref Side tokenSide)
		{
			Point		pointToHitTest = new Point (nX, nY);
			Rectangle	testRectangle;

			switch (this.Rotation)
			{
				case 0:
				{
					testRectangle = new Rectangle (28, 7, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("N");
						return true;
					}

					testRectangle = new Rectangle (14, 36, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("SE");
						return true;
					}

					return false;
				}

				case 60:
				{
					testRectangle = new Rectangle (11, 17, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("NW");
						return true;
					}

					testRectangle = new Rectangle (44, 16, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("SW");
						return true;
					}

					return false;
				}

				case 120:
				{
					testRectangle = new Rectangle (27, 6, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("N");
						return true;
					}

					testRectangle = new Rectangle (44, 32, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("SE");
						return true;
					}

					return false;
				}

				case 180:
				{
					testRectangle = new Rectangle (28, 42, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("N");
						return true;
					}

					testRectangle = new Rectangle (44, 12, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("NE");
						return true;
					}

					return false;
				}

				case 240:
				{
					testRectangle = new Rectangle (14, 32, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("NE");
						return true;
					}

					testRectangle = new Rectangle (46, 33, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("SE");
						return true;
					}

					return false;
				}

				case 300:
				{
					testRectangle = new Rectangle (31, 42, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("S");
						return true;
					}

					testRectangle = new Rectangle (14, 16, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("NW");
						return true;
					}

					return false;
				}

				default:
					GameException	illegalRotationException = new GameException ("Illegal rotation.");
					throw (illegalRotationException);
			}
		}

		public bool SetSideFromTileCoordinatesTile68 (int nX, int nY, ref Side tokenSide)
		{
			Point		pointToHitTest = new Point (nX, nY);
			Rectangle	testRectangle;

			switch (this.Rotation)
			{
				case 0:
				{
					testRectangle = new Rectangle (29, 42, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("S");
						return true;
					}

					testRectangle = new Rectangle (12, 14, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("SE");
						return true;
					}

					return false;
				}

				case 60:
				{
					testRectangle = new Rectangle (12, 33, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("NE");
						return true;
					}

					testRectangle = new Rectangle (29, 7, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("S");
						return true;
					}

					return false;
				}

				case 120:
				{
					testRectangle = new Rectangle (12, 14, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("SE");
						return true;
					}

					testRectangle = new Rectangle (44, 14, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("SW");
						return true;
					}

					return false;
				}

				case 180:
				{
					testRectangle = new Rectangle (29, 8, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("N");
						return true;
					}

					testRectangle = new Rectangle (45, 33, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("NW");
						return true;
					}

					return false;
				}

				case 240:
				{
					testRectangle = new Rectangle (29, 42, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("N");
						return true;
					}

					testRectangle = new Rectangle (44, 17, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("NE");
						return true;
					}

					return false;
				}

				case 300:
				{
					testRectangle = new Rectangle (43, 32, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("SE");
						return true;
					}

					testRectangle = new Rectangle (14, 33, Token.tokenWidth, Token.tokenHeight);
					testRectangle.Inflate (2, 2);

					if (testRectangle.Contains (pointToHitTest))
					{
						tokenSide.SetDirection ("NE");
						return true;
					}

					return false;
				}

				default:
					GameException	illegalRotationException = new GameException ("Illegal rotation.");
					throw (illegalRotationException);
			}
		}

		public bool SetSideFromTileCoordinatesTile120 (int nX, int nY, ref Side tokenSide)
		{
			Point		pointToHitTest = new Point (nX, nY);
			Rectangle	testRectangle;

			testRectangle = new Rectangle (39, 8, Token.tokenWidth, Token.tokenHeight);
			testRectangle.Inflate (2, 2);

			if (testRectangle.Contains (pointToHitTest))
			{
				tokenSide.SetDirection ("NE");
				return true;
			}

			return false;
		}

		public bool SetSideFromTileCoordinatesTile122 (int nX, int nY, ref Side tokenSide)
		{
			Point		pointToHitTest = new Point (nX, nY);
			Rectangle	testRectangle;

			testRectangle = new Rectangle (9, 22, Token.tokenWidth, Token.tokenHeight);
			testRectangle.Inflate (1, 1);

			if (testRectangle.Contains (pointToHitTest))
			{
				tokenSide.SetDirection ("NW");
				return true;
			}

			testRectangle = new Rectangle (39, 7, Token.tokenWidth, Token.tokenHeight);
			testRectangle.Inflate (1, 1);

			if (testRectangle.Contains (pointToHitTest))
			{
				tokenSide.SetDirection ("N");
				return true;
			}

			testRectangle = new Rectangle (49, 27, Token.tokenWidth, Token.tokenHeight);
			testRectangle.Inflate (1, 1);

			if (testRectangle.Contains (pointToHitTest))
			{
				tokenSide.SetDirection ("NE");
				return true;
			}

			return false;
		}

		public bool SetSideFromTileCoordinatesTile124 (int nX, int nY, ref Side tokenSide)
		{
			Point		pointToHitTest = new Point (nX, nY);
			Rectangle	testRectangle;

			testRectangle = new Rectangle (14, 21, Token.tokenWidth, Token.tokenHeight);
			testRectangle.Inflate (1, 1);

			if (testRectangle.Contains (pointToHitTest))
			{
				tokenSide.SetDirection ("NW");
				return true;
			}

			testRectangle = new Rectangle (33, 10, Token.tokenWidth, Token.tokenHeight);
			testRectangle.Inflate (1, 1);

			if (testRectangle.Contains (pointToHitTest))
			{
				tokenSide.SetDirection ("N");
				return true;
			}

			testRectangle = new Rectangle (44, 29, Token.tokenWidth, Token.tokenHeight);
			testRectangle.Inflate (1, 1);

			if (testRectangle.Contains (pointToHitTest))
			{
				tokenSide.SetDirection ("NE");
				return true;
			}

			return false;
		}

		public bool SetSideFromTileCoordinates (int nX, int nY, ref Side tokenSide)
		{
			if (this.SeperateCities)	// Only care about token side for seperated cities.
			{
				if (_tile == null)
				{
					if (this.City == "Toronto")
					{
						tokenSide.SetDirection ("NE");
						return true;
					}
				}
				else
				{
					switch (_tile.Name)
					{
						case "59":
						{
							return SetSideFromTileCoordinatesTile59 (nX, nY, ref tokenSide);
						}

						case "64":
						{
							return SetSideFromTileCoordinatesTile64 (nX, nY, ref tokenSide);
						}

						case "65":
						{
							return SetSideFromTileCoordinatesTile65 (nX, nY, ref tokenSide);
						}

						case "66":
						{
							return SetSideFromTileCoordinatesTile66 (nX, nY, ref tokenSide);
						}

						case "67":
						{
							return SetSideFromTileCoordinatesTile67 (nX, nY, ref tokenSide);
						}

						case "68":
						{
							return SetSideFromTileCoordinatesTile68 (nX, nY, ref tokenSide);
						}

						case "120":
						{
							return SetSideFromTileCoordinatesTile120 (nX, nY, ref tokenSide);
						}

						case "122":
						{
							return SetSideFromTileCoordinatesTile122 (nX, nY, ref tokenSide);
						}

						case "123": // Hamilton is no longer seperated, it's 3 combined cities.  Just return North.
						{
							tokenSide.SetDirection ("N");
							return true;
						}

						case "124":
						{
							return SetSideFromTileCoordinatesTile124 (nX, nY, ref tokenSide);
						}

						default:
							GameException	e = new GameException ("Tile not found.");
							throw (e);
					}
				}
			}

			return false;
		}

		public bool ReserveSpotForHomeStation (Game game, out Side sideToReserve)
		{
			bool	bReturn = false;
			sideToReserve = null;

			foreach (PublicCompany company in game.PublicCompanies)
			{
				if (company.Home == this.Location)
				{
					if (company.TokensPlayed == 0)	// Has not laid a token yet.
					{
						bReturn = true;

						if (company.StartSideSpecified)
							sideToReserve = company.StartSide;
					}

					break;
				}
			}

			return bReturn;
		}

		public void OffsetTokenInHex (int nCount, ref int nLeft, ref int nTop, Side side)
		{
			if (this.SeperateCities  || ((this.Tile != null) && this.Tile.Name.Equals ("123") && this.Tile.TileName.Equals ("Hamilton")))
			{
				GetSeperateCityTokenLocation (nCount, ref nLeft, ref nTop, side);
			}
			else
			{
				nLeft += (hexWidth - Token.tokenWidth) / 2;			// First, put it in the 'middle' of the hex, taking into account the token size.
				nTop += hexHeight / 2 - Token.tokenHeight / 2;

				if (this._tile == null)	// No tile laid yet on this hex?
					return;

				switch (this._tile.Color)
				{
					case WebApplication.Tile.eTileColor.Yellow:	// One token, always in center except for Toronto in 1856, New York in 1830.

						break;

					case WebApplication.Tile.eTileColor.Green:	// One token, always in center except for Toronto in 1856, New York in 1830.

						ComputeGreenBrownSingleCityTokenOffset (nCount, ref nLeft, ref nTop);
						break;

					case WebApplication.Tile.eTileColor.Brown:
						ComputeGreenBrownSingleCityTokenOffset (nCount, ref nLeft, ref nTop);
						break;

					case WebApplication.Tile.eTileColor.Gray:
						//						ComputeGrayCityTokenOffset (nCount, ref nLeft, ref nTop);
						break;

					default:
						GameException	e = new GameException ("Illegal color for tile.");
						throw (e);
				}
			}
		}
	}
}
